import backtrader as bt
from .DbOprate import DbOprate

class LowPointStrategy(bt.Strategy):
    """
    D1:=20;
    D2:=10;
    X_13:=CLOSE=LLV(CLOSE,D1);{是否20日最低收盘价}
    X_14:BARSLAST(FILTER(CROSS(0.8,X_13),D2))+1;{距离最近一次“股价从创阶段新低后反弹”的信号，已经过去了多少根K线};

    X_15:=X_14=1;
    DRAWICON(X_15,LOW*0.98,1);{阶段性低点第二天出现买点（确定性不足）};
    """
    params = (
        ('d1', 20),      # 20日周期
        ('d2', 10),      # 10日周期 - 过滤周期
        ('hold_days', 3), # 持有天数
        ('profit_target', 0.05), # 盈利目标 10%
        ('stop_loss', 0.03),     # 止损 3%
        ('position_ratio', 0.9), # 使用资金比例 90% - 降低比例避免超买
    )

    def log(self, txt, dt=None):
        dt = dt or self.datas[0].datetime.date(0)
        print(f'{dt.isoformat()}, {txt}')

    def __init__(self):
        self.data_close = self.datas[0].close

        # X_13: close 是否等于过去D1天最低
        self.llv_close = bt.indicators.Lowest(self.data_close, period=self.p.d1)
        self.x_13 = (self.data_close == self.llv_close)
        
        # FILTER相关变量
        self.filter_counter = 0  # 过滤计数器，0表示不在过滤期内
        self.last_signal_bar = -1  # 记录最近一次信号出现的bar位置
        
        # 交易相关变量
        self.buy_price = None
        self.buy_date = None
        self.hold_bars = 0

    def next(self):
        current_date = self.datas[0].datetime.date(0)
        current_bar = len(self)  # 当前bar的位置
        current_price = self.data_close[0]

        # 获取当前资金状态
        cash = max(0, self.broker.getcash())
        position_size = self.position.size
        position_value = position_size * current_price if position_size > 0 else 0
        
        # 更新过滤计数器
        if self.filter_counter > 0:
            self.filter_counter -= 1

        # 计算X_14值
        if self.last_signal_bar == -1:
            x_14_value = 0
        else:
            x_14_value = current_bar - self.last_signal_bar

        # 检查持仓情况
        if position_size > 0 and self.buy_price is not None:
            self.hold_bars += 1
            
            # 检查卖出条件
            should_sell = False
            sell_reason = ""
            
            # 止损止盈逻辑
            if self.hold_bars >= self.p.hold_days:
                should_sell = True
                sell_reason = f"持有满{self.p.hold_days}天"
            elif (current_price - self.buy_price) / self.buy_price >= self.p.profit_target:
                should_sell = True
                sell_reason = f"盈利达到{self.p.profit_target*100}%"
            elif (self.buy_price - current_price) / self.buy_price >= self.p.stop_loss:
                should_sell = True
                sell_reason = f"亏损达到{self.p.stop_loss*100}%"
            
            # 执行卖出
            if should_sell:
                size = position_size
                profit = (current_price - self.buy_price) * size
                
                self.log(f'*** 卖出信号 *** 原因: {sell_reason}, 价格: {current_price:.2f}, 数量: {size}')
                
                # 执行卖出
                self.sell(size=size)
                
                # 重置变量
                self.buy_price = None
                self.buy_date = None
                self.hold_bars = 0
        else:
            # 没有持仓时检查买入信号
            if len(self.x_13) > 1:
                x_13_prev = self.x_13[-1]
                x_13_curr = self.x_13[0]
                
                # CROSS(0.8, X_13): X_13从1变为0
                x_13_1 = (x_13_prev == 1) and (x_13_curr == 0)

                # 检查是否在过滤期内
                if self.filter_counter <= 0 and x_13_1 and cash > 1000:  # 提高最低资金要求
                    self.log(f'*** X_13_1 有效信号触发 ***')
                    self.log(f'*** 可用资金: {cash:.2f}, 当前价格: {current_price:.2f}')
                    
                    # 使用更保守的计算方法
                    use_cash = cash * self.p.position_ratio
                    # 计算最大可买数量（100股为单位）
                    max_size = int((use_cash / current_price) / 100) * 100
                    
                    # 只要出现买点就存入数据库（不需要真正执行交易）
                    if max_size >= 100:
                        size = min(max_size, max_size)  # 可以在这里进一步限制
                        required_cash = size * current_price
                        
                        # 存入数据库 - 买点信号
                        try:
                            result = {
                                'strategy': 'LowPointStrategy',
                                'stock_code': self.datas[0]._name,
                                'op_act': 'buy_signal',  # 标记为买点信号，不是真实交易
                                'op_price': float(current_price),
                                'op_num': int(size),
                                'op_comm': 0.0,
                                'op_dt': current_date.isoformat(),
                                'reason': 'X_13_1_CROSS_FILTER',
                                'x_14_value': float(x_14_value),
                                'can_use_money': float(max(0, cash)),
                                'init_cash': float(self.broker.startingcash),
                                'stock_num': int(max(0, position_size)),
                                'stock_amount': float(max(0, position_value)),
                                'profitable': 0.0
                            }
                            DbOprate.save_result_to_mysql(result)
                            self.log(f'*** 买点信号已存入数据库 *** 价格: {current_price:.2f}, 建议数量: {size}')
                        except Exception as e:
                            self.log(f'*** 数据库存储失败 *** 错误: {str(e)}')
                    
                    # 实际交易逻辑（根据你的需求决定是否执行）
                    # 如果要真正执行交易，取消下面的注释
                    '''
                    # 限制最大买入数量，确保不会超买
                    if max_size >= 100:
                        size = min(max_size, max_size)  # 可以在这里进一步限制
                        required_cash = size * current_price
                        
                        # 再次确认资金足够
                        if cash >= required_cash * 1.01:  # 预留1%的安全边际
                            self.log(f'*** 买入执行 *** 价格: {current_price:.2f}, 数量: {size}')
                            
                            # 执行买入
                            self.buy(size=size)
                            
                            self.buy_price = current_price
                            self.buy_date = current_date
                            self.hold_bars = 0
                            
                            # 记录信号位置和启动过滤期
                            self.last_signal_bar = current_bar
                            self.filter_counter = self.p.d2
                        else:
                            self.log(f'*** 资金检查失败 *** 可用: {cash:.2f}, 需要: {required_cash:.2f}')
                    else:
                        self.log(f'*** 可买数量不足 *** 最大可买: {max_size}股')
                    '''

    def notify_order(self, order):
        if order.status in [order.Completed]:
            if order.isbuy():
                self.log(f'*** 买入订单完成 *** 价格: {order.executed.price:.2f}, 数量: {order.executed.size}')
            elif order.issell():
                self.log(f'*** 卖出订单完成 *** 价格: {order.executed.price:.2f}, 数量: {order.executed.size}')
        elif order.status in [order.Canceled, order.Margin, order.Rejected]:
            self.log(f'*** 订单失败 *** 状态: {order.Status[order.status]}')

    def notify_trade(self, trade):
        if trade.isclosed:
            profit = trade.pnl
            self.log(f'*** 交易完成 *** 盈亏: {profit:.2f}')
